<?php
/**
 * Created by PhpStorm.
 * User: huangxianyun
 * Date: 2022/11/28
 * Time: 下午6:33
 */

namespace EasySwoole\EasySwoole;

use App\Crontab\TestCrontab;
use App\Utility\MyRedisQueue;
use EasySwoole\Crontab\Exception\Exception;
use EasySwoole\EasySwoole\Swoole\EventRegister;
use EasySwoole\EasySwoole\AbstractInterface\Event;
use EasySwoole\FastDb\FastDb;
use EasySwoole\Http\Request;
use EasySwoole\Http\Response;
use EasySwoole\Component\Di;

//IOC容器
use EasySwoole\AtomicLimit\AtomicLimit;

//限流器
use EasySwoole\Pool\Config as PoolConfig;

//连接池配置
use App\Pool\RedisPool;

//自定义的REDIS连接池
use EasySwoole\Pool\Manager as PoolManager;

//连接池管理对象
use EasySwoole\Http\Message\Status as HttpStatusCode;

//HTTP状态码
use App\Process\QueueProcess;

//消费者进程
class EasySwooleEvent implements Event
{
    public static function initialize(): void
    {
        date_default_timezone_set('Asia/Shanghai');

        ###### 初始化数据库ORM 注册mysql ######
        $dbConfig = new \EasySwoole\FastDb\Config(Config::getInstance()->getConf('MYSQL'));//获取mysql配置
        FastDb::getInstance()->addDb($dbConfig);//连接mysql

        //处理网络连接
        Di::getInstance()->set(SysConst::HTTP_GLOBAL_ON_REQUEST, function (Request $request, Response $response): bool {
            ###### 处理请求的跨域问题 ######
            $response->withHeader('Access-Control-Allow-Origin', '*');
            $response->withHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
            $response->withHeader('Access-Control-Allow-Credentials', 'true');
            $response->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With');
            if ($request->getMethod() === 'OPTIONS') {
                $response->withStatus(HttpStatusCode::CODE_OK);
                return false;
            }
            return true;
        });


    }

    /**
     * @throws Exception
     * @throws \EasySwoole\Pool\Exception\Exception
     */
    public static function mainServerCreate(EventRegister $register): void
    {
        $register->add($register::onWorkerStart, function () {
            // 数据库连接预热
            FastDb::getInstance()->preConnect();
            //当刚启动服务，出现过大的并发时，可能会突然需要几十个甚至上百个连接，这时为了让创建连接的时间分散，我们可以对redis连接预热，可以通过调用 keepMin 方法进行预热启动连接
            PoolManager::getInstance()->get('redis')->keepMin();
        });

        ###### 注册连接池管理对象 ######
        //获取REDIS配置对象
        $redisConfig = new \EasySwoole\Redis\Config(Config::getInstance()->getConf('REDIS'));
        //获取连接池的配置
        $poolConfig = new PoolConfig();
        $redisPool = new RedisPool($poolConfig, $redisConfig);
        //将redis注入到pool连接池管理对象中
        PoolManager::getInstance()->register($redisPool, 'redis');
        ###### 注册一个定时任务 ######
        // 配置定时任务
        $crontabConfig = new \EasySwoole\Crontab\Config();
        // 1.设置执行定时任务的 socket 服务的 socket 文件存放的位置，默认值为 当前文件所在目录
        // 这里设置为框架的 Temp 目录
        $crontabConfig->setTempDir(EASYSWOOLE_TEMP_DIR);
        // 2.设置执行定时任务的 socket 服务的名称，默认值为 'EasySwoole'
        $crontabConfig->setServerName('EasySwoole');
        // 3.设置用来执行定时任务的 worker 进程数，默认值为 3
        $crontabConfig->setWorkerNum(3);
        // 4.设置定时任务执行出现异常的异常捕获回调
        $crontabConfig->setOnException(function (\Throwable $throwable) {
            // 定时任务执行发生异常时触发（如果未在定时任务类的 onException 中进行捕获异常则会触发此异常回调）
        });

        // 创建定时任务实例
        $crontab = \EasySwoole\EasySwoole\Crontab\Crontab::getInstance($crontabConfig);
        // 注册定时任务
        $crontab->register(new TestCrontab());

        ###### 注册一个消息队列 ######
        //注册redis驱动队列
        // 配置 队列驱动器
        $driver = new \EasySwoole\Queue\Driver\RedisQueue($redisConfig);
        MyRedisQueue::getInstance($driver);
        // 注册一个消费进程
        $processConfig = new \EasySwoole\Component\Process\Config([
            'processName'     => 'QueueProcess', // 设置 自定义进程名称
            'processGroup'    => 'Queue', // 设置 自定义进程组名称
            'enableCoroutine' => true, // 设置 自定义进程自动开启协程
        ]);
        \EasySwoole\Component\Process\Manager::getInstance()->addProcess(new QueueProcess($processConfig));

        ###### 配置限流器 ######
        // 注意，本例子是用一个自定义进程内加定时器来实现计数定时重置，实际上用一个进程来做这件事情有点不值得，因此实际生产可以指定一个 worker，设置定时器来实现。
        $limit = new AtomicLimit();
        /** 为方便测试，（全局的）限制设置为 10 */
        $limit->setLimitQps(10);
        $limit->attachServer(ServerManager::getInstance()->getSwooleServer());
        Di::getInstance()->set('auto_limiter', $limit);

    }

    public static function onRequest(Request $request, Response $response): bool
    {
        // TODO: Implement onRequest() method.
        return true;
    }

    public static function afterRequest(Request $request, Response $response): void
    {
        // TODO: Implement afterAction() method.
    }
}